// 性能优化系统 - Stage 3
// 对象池、内存管理、FPS稳定性优化

export interface Poolable {
    reset(): void;
    isActive(): boolean;
    setActive(active: boolean): void;
}

export class ObjectPool<T extends Poolable> {
    private pool: T[] = [];
    private factory: () => T;
    private maxSize: number;
    private activeObjects = new Set<T>();

    constructor(factory: () => T, initialSize: number = 10, maxSize: number = 100) {
        this.factory = factory;
        this.maxSize = maxSize;
        
        // 预分配对象
        for (let i = 0; i < initialSize; i++) {
            const obj = this.factory();
            obj.setActive(false);
            this.pool.push(obj);
        }
        
        console.log(`🏊 对象池初始化: ${initialSize} 个对象, 最大 ${maxSize} 个`);
    }

    public get(): T | null {
        let obj: T;
        
        if (this.pool.length > 0) {
            obj = this.pool.pop()!;
        } else if (this.activeObjects.size < this.maxSize) {
            obj = this.factory();
        } else {
            console.warn('⚠️ 对象池已满，无法分配新对象');
            return null;
        }
        
        obj.reset();
        obj.setActive(true);
        this.activeObjects.add(obj);
        return obj;
    }

    public release(obj: T): void {
        if (this.activeObjects.has(obj)) {
            obj.setActive(false);
            this.activeObjects.delete(obj);
            
            if (this.pool.length < this.maxSize) {
                this.pool.push(obj);
            }
        }
    }

    public releaseAll(): void {
        for (const obj of this.activeObjects) {
            obj.setActive(false);
            if (this.pool.length < this.maxSize) {
                this.pool.push(obj);
            }
        }
        this.activeObjects.clear();
    }

    public getActiveCount(): number {
        return this.activeObjects.size;
    }

    public getPoolSize(): number {
        return this.pool.length;
    }

    public getTotalCapacity(): number {
        return this.maxSize;
    }
}

export class FrameRateManager {
    private targetFPS = 60;
    private frameTime = 1000 / this.targetFPS;
    private lastFrameTime = 0;
    private deltaTime = 0;
    private frameCount = 0;
    private fpsHistory: number[] = [];
    private currentFPS = 60;
    private skipFrames = 0;
    private adaptiveQuality = true;

    // 性能指标
    private performanceMetrics = {
        avgFrameTime: 16.67,
        maxFrameTime: 16.67,
        minFrameTime: 16.67,
        droppedFrames: 0,
        totalFrames: 0,
        memoryUsage: 0
    };

    public update(currentTime: number): boolean {
        this.deltaTime = currentTime - this.lastFrameTime;
        
        // 限制最大delta time，避免大跳跃
        if (this.deltaTime > 100) {
            this.deltaTime = 16.67; // 60 FPS
        }
        
        this.lastFrameTime = currentTime;
        this.frameCount++;
        this.performanceMetrics.totalFrames++;

        // 更新FPS历史
        if (this.frameCount % 10 === 0) {
            const fps = 1000 / this.deltaTime;
            this.fpsHistory.push(fps);
            
            if (this.fpsHistory.length > 60) {
                this.fpsHistory.shift();
            }
            
            this.currentFPS = this.fpsHistory.reduce((a, b) => a + b, 0) / this.fpsHistory.length;
        }

        // 更新性能指标
        this.updatePerformanceMetrics();

        // 自适应质量调整
        if (this.adaptiveQuality) {
            this.adjustQuality();
        }

        // 帧率控制
        return this.shouldRenderFrame();
    }

    private updatePerformanceMetrics(): void {
        this.performanceMetrics.avgFrameTime = this.fpsHistory.length > 0 
            ? this.fpsHistory.reduce((a, b) => a + 1000/b, 0) / this.fpsHistory.length
            : 16.67;
        
        if (this.deltaTime > this.performanceMetrics.maxFrameTime) {
            this.performanceMetrics.maxFrameTime = this.deltaTime;
        }
        
        if (this.deltaTime < this.performanceMetrics.minFrameTime) {
            this.performanceMetrics.minFrameTime = this.deltaTime;
        }

        // 估算内存使用
        if ((performance as any).memory) {
            this.performanceMetrics.memoryUsage = (performance as any).memory.usedJSHeapSize / 1024 / 1024;
        }
    }

    private adjustQuality(): void {
        if (this.currentFPS < 45) {
            // 降低质量
            this.onQualityChange?.('low');
        } else if (this.currentFPS > 55) {
            // 提高质量
            this.onQualityChange?.('high');
        }
    }

    private shouldRenderFrame(): boolean {
        if (this.currentFPS < 30) {
            // 严重掉帧，跳过一些帧
            this.skipFrames++;
            if (this.skipFrames % 2 === 0) {
                this.performanceMetrics.droppedFrames++;
                return false;
            }
        }
        return true;
    }

    public getDeltaTime(): number {
        return Math.min(this.deltaTime, 33.33); // 最大30 FPS
    }

    public getCurrentFPS(): number {
        return this.currentFPS;
    }

    public getPerformanceMetrics(): typeof this.performanceMetrics {
        return { ...this.performanceMetrics };
    }

    public setTargetFPS(fps: number): void {
        this.targetFPS = fps;
        this.frameTime = 1000 / fps;
    }

    public setAdaptiveQuality(enabled: boolean): void {
        this.adaptiveQuality = enabled;
    }

    // 质量变化回调
    public onQualityChange?: (quality: 'low' | 'medium' | 'high') => void;
}

export class MemoryManager {
    private allocatedObjects = new Map<string, any[]>();
    private memoryThreshold = 100; // MB
    private gcInterval = 10000; // 10秒
    private lastGCTime = 0;

    public trackObject(category: string, obj: any): void {
        if (!this.allocatedObjects.has(category)) {
            this.allocatedObjects.set(category, []);
        }
        this.allocatedObjects.get(category)!.push(obj);
    }

    public releaseCategory(category: string): void {
        const objects = this.allocatedObjects.get(category);
        if (objects) {
            objects.length = 0;
        }
    }

    public forceGarbageCollection(): void {
        // 清理未使用的对象
        for (const [category, objects] of this.allocatedObjects) {
            for (let i = objects.length - 1; i >= 0; i--) {
                const obj = objects[i];
                if (obj && typeof obj.isActive === 'function' && !obj.isActive()) {
                    objects.splice(i, 1);
                }
            }
        }
        
        // 触发浏览器GC（如果可用）
        if ((window as any).gc) {
            (window as any).gc();
        }
        
        this.lastGCTime = performance.now();
        console.log('🗑️ 执行内存清理');
    }

    public update(currentTime: number): void {
        if (currentTime - this.lastGCTime > this.gcInterval) {
            const memoryUsage = this.getMemoryUsage();
            if (memoryUsage > this.memoryThreshold) {
                this.forceGarbageCollection();
            }
        }
    }

    public getMemoryUsage(): number {
        if ((performance as any).memory) {
            return (performance as any).memory.usedJSHeapSize / 1024 / 1024;
        }
        return 0;
    }

    public getObjectCount(): Map<string, number> {
        const counts = new Map<string, number>();
        for (const [category, objects] of this.allocatedObjects) {
            counts.set(category, objects.length);
        }
        return counts;
    }
}

export class RenderOptimizer {
    private canvas: HTMLCanvasElement;
    private ctx: CanvasRenderingContext2D;
    private offscreenCanvas: OffscreenCanvas | HTMLCanvasElement;
    private offscreenCtx: CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D;
    private dirtyRegions: Set<string> = new Set();
    private lastRenderTime = 0;
    private cullingEnabled = true;
    private viewportBounds = { x: 0, y: 0, width: 0, height: 0 };

    constructor(canvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D) {
        this.canvas = canvas;
        this.ctx = ctx;
        this.viewportBounds = {
            x: 0,
            y: 0,
            width: canvas.width,
            height: canvas.height
        };

        // 创建离屏画布
        try {
            this.offscreenCanvas = new OffscreenCanvas(canvas.width, canvas.height);
            this.offscreenCtx = this.offscreenCanvas.getContext('2d')!;
        } catch {
            // 回退到普通画布
            this.offscreenCanvas = document.createElement('canvas');
            this.offscreenCanvas.width = canvas.width;
            this.offscreenCanvas.height = canvas.height;
            this.offscreenCtx = this.offscreenCanvas.getContext('2d')!;
        }

        console.log('🎨 渲染优化器初始化完成');
    }

    public isInViewport(x: number, y: number, width: number, height: number): boolean {
        if (!this.cullingEnabled) return true;
        
        return !(x + width < this.viewportBounds.x ||
                x > this.viewportBounds.x + this.viewportBounds.width ||
                y + height < this.viewportBounds.y ||
                y > this.viewportBounds.y + this.viewportBounds.height);
    }

    public markDirty(region: string): void {
        this.dirtyRegions.add(region);
    }

    public clearDirty(): void {
        this.dirtyRegions.clear();
    }

    public shouldRender(region: string): boolean {
        return this.dirtyRegions.has(region) || this.dirtyRegions.has('all');
    }

    public getOffscreenContext(): CanvasRenderingContext2D | OffscreenCanvasRenderingContext2D {
        return this.offscreenCtx;
    }

    public blitToMain(sourceX = 0, sourceY = 0, width?: number, height?: number, 
                     destX = 0, destY = 0): void {
        const w = width || this.canvas.width;
        const h = height || this.canvas.height;
        
        if (this.offscreenCanvas instanceof HTMLCanvasElement) {
            this.ctx.drawImage(this.offscreenCanvas, sourceX, sourceY, w, h, destX, destY, w, h);
        } else {
            // OffscreenCanvas to ImageBitmap
            this.offscreenCanvas.transferToImageBitmap();
        }
    }

    public setCullingEnabled(enabled: boolean): void {
        this.cullingEnabled = enabled;
    }

    public updateViewport(x: number, y: number, width: number, height: number): void {
        this.viewportBounds = { x, y, width, height };
    }
}

export class PerformanceMonitor {
    private metrics = {
        fps: 0,
        frameTime: 0,
        memory: 0,
        entities: 0,
        particles: 0,
        drawCalls: 0,
        missedFrames: 0
    };

    private history = {
        fps: [] as number[],
        frameTime: [] as number[],
        memory: [] as number[]
    };

    private updateInterval = 1000; // 1秒
    private lastUpdate = 0;

    public update(currentTime: number, frameManager: FrameRateManager): void {
        if (currentTime - this.lastUpdate > this.updateInterval) {
            this.metrics.fps = frameManager.getCurrentFPS();
            this.metrics.frameTime = frameManager.getDeltaTime();
            
            if ((performance as any).memory) {
                this.metrics.memory = (performance as any).memory.usedJSHeapSize / 1024 / 1024;
            }

            // 更新历史记录
            this.history.fps.push(this.metrics.fps);
            this.history.frameTime.push(this.metrics.frameTime);
            this.history.memory.push(this.metrics.memory);

            // 限制历史记录长度
            const maxHistory = 60; // 60秒
            if (this.history.fps.length > maxHistory) {
                this.history.fps.shift();
                this.history.frameTime.shift();
                this.history.memory.shift();
            }

            this.lastUpdate = currentTime;
        }
    }

    public setEntityCount(count: number): void {
        this.metrics.entities = count;
    }

    public setParticleCount(count: number): void {
        this.metrics.particles = count;
    }

    public incrementDrawCalls(): void {
        this.metrics.drawCalls++;
    }

    public resetDrawCalls(): void {
        this.metrics.drawCalls = 0;
    }

    public getMetrics(): typeof this.metrics {
        return { ...this.metrics };
    }

    public getHistory(): typeof this.history {
        return {
            fps: [...this.history.fps],
            frameTime: [...this.history.frameTime],
            memory: [...this.history.memory]
        };
    }

    public getAverages(): { fps: number; frameTime: number; memory: number } {
        return {
            fps: this.history.fps.reduce((a, b) => a + b, 0) / this.history.fps.length || 0,
            frameTime: this.history.frameTime.reduce((a, b) => a + b, 0) / this.history.frameTime.length || 0,
            memory: this.history.memory.reduce((a, b) => a + b, 0) / this.history.memory.length || 0
        };
    }

    public renderDebugInfo(ctx: CanvasRenderingContext2D, x: number, y: number): void {
        const metrics = this.getMetrics();
        const averages = this.getAverages();

        ctx.save();
        ctx.fillStyle = 'rgba(0, 0, 0, 0.8)';
        ctx.fillRect(x, y, 200, 120);

        ctx.fillStyle = '#00ff00';
        ctx.font = '12px monospace';
        ctx.textAlign = 'left';

        let lineY = y + 15;
        const lineHeight = 14;

        ctx.fillText(`FPS: ${metrics.fps.toFixed(1)} (${averages.fps.toFixed(1)})`, x + 5, lineY);
        lineY += lineHeight;
        
        ctx.fillText(`Frame: ${metrics.frameTime.toFixed(1)}ms`, x + 5, lineY);
        lineY += lineHeight;
        
        ctx.fillText(`Memory: ${metrics.memory.toFixed(1)}MB`, x + 5, lineY);
        lineY += lineHeight;
        
        ctx.fillText(`Entities: ${metrics.entities}`, x + 5, lineY);
        lineY += lineHeight;
        
        ctx.fillText(`Particles: ${metrics.particles}`, x + 5, lineY);
        lineY += lineHeight;
        
        ctx.fillText(`Draw Calls: ${metrics.drawCalls}`, x + 5, lineY);
        lineY += lineHeight;

        ctx.restore();
    }
}

// 主性能优化系统
export class PerformanceOptimizationSystem {
    private frameManager: FrameRateManager;
    private memoryManager: MemoryManager;
    private renderOptimizer: RenderOptimizer;
    private monitor: PerformanceMonitor;
    private pools = new Map<string, ObjectPool<any>>();

    constructor(canvas: HTMLCanvasElement, ctx: CanvasRenderingContext2D) {
        this.frameManager = new FrameRateManager();
        this.memoryManager = new MemoryManager();
        this.renderOptimizer = new RenderOptimizer(canvas, ctx);
        this.monitor = new PerformanceMonitor();

        console.log('⚡ 性能优化系统初始化完成');
    }

    public createPool<T extends Poolable>(name: string, factory: () => T, 
                                         initialSize = 10, maxSize = 100): ObjectPool<T> {
        const pool = new ObjectPool(factory, initialSize, maxSize);
        this.pools.set(name, pool);
        return pool;
    }

    public getPool<T extends Poolable>(name: string): ObjectPool<T> | undefined {
        return this.pools.get(name);
    }

    public update(currentTime: number): boolean {
        const shouldRender = this.frameManager.update(currentTime);
        this.memoryManager.update(currentTime);
        this.monitor.update(currentTime, this.frameManager);
        
        // 更新池统计
        let totalEntities = 0;
        for (const pool of this.pools.values()) {
            totalEntities += pool.getActiveCount();
        }
        this.monitor.setEntityCount(totalEntities);

        return shouldRender;
    }

    public getDeltaTime(): number {
        return this.frameManager.getDeltaTime();
    }

    public getFrameManager(): FrameRateManager {
        return this.frameManager;
    }

    public getMemoryManager(): MemoryManager {
        return this.memoryManager;
    }

    public getRenderOptimizer(): RenderOptimizer {
        return this.renderOptimizer;
    }

    public getMonitor(): PerformanceMonitor {
        return this.monitor;
    }

    public forceGC(): void {
        this.memoryManager.forceGarbageCollection();
    }

    public setQualityLevel(level: 'low' | 'medium' | 'high'): void {
        switch (level) {
            case 'low':
                this.frameManager.setTargetFPS(30);
                this.renderOptimizer.setCullingEnabled(true);
                break;
            case 'medium':
                this.frameManager.setTargetFPS(45);
                this.renderOptimizer.setCullingEnabled(true);
                break;
            case 'high':
                this.frameManager.setTargetFPS(60);
                this.renderOptimizer.setCullingEnabled(false);
                break;
        }
        console.log(`🎯 质量等级设置为: ${level}`);
    }

    public getPerformanceReport(): {
        fps: number;
        memory: number;
        entities: number;
        pools: { [key: string]: { active: number; total: number } };
    } {
        const metrics = this.monitor.getMetrics();
        const poolStats: { [key: string]: { active: number; total: number } } = {};
        
        for (const [name, pool] of this.pools) {
            poolStats[name] = {
                active: pool.getActiveCount(),
                total: pool.getTotalCapacity()
            };
        }

        return {
            fps: metrics.fps,
            memory: metrics.memory,
            entities: metrics.entities,
            pools: poolStats
        };
    }
}
